﻿

using Admin.NET.Core;
using Admin.NET.Core.Service.Hub;
using FluentEmail.Core;
using Furion;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using IotContract.Models.Webs;
using IotContract.Socket;
using IotFun.Const;
using IotFun.Entity;
using IotFun.Services;
using IotFun.Views.ProgramAll.Dto;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using NewLife;
using NewLife.Http;
using System.Net.WebSockets;

using XT.Common.Models.SignalR;

namespace IotFun.Views.ProgramAll;
/// <summary>
/// 程序管理服务
/// </summary>
[ApiDescriptionSettings(IotConst.GroupName)]
public class ProgramInfoService : IDynamicApiController, ITransient,IDisposable
{
    private readonly SqlSugarRepository<ProgramInfo> _rep;


    private readonly GrpcService _grpcService;

    private readonly MessageHubService _hubService;

    private System.Net.WebSockets.WebSocket _socket;
    public ProgramInfoService(SqlSugarRepository<ProgramInfo> rep,GrpcService grpcService, MessageHubService hubService)
    {
        _rep = rep;
        _grpcService = grpcService;
        _hubService = hubService;

        _hubService.MessageEvent += _hubService_MessageEvent;
        _hubService.RemoteLogEvent += _hubService_RemoteLogEvent;
    }

    public void Dispose()
    {
        _hubService.MessageEvent -= _hubService_MessageEvent;
        _hubService.RemoteLogEvent -= _hubService_RemoteLogEvent;
        _source?.Cancel();
        _source?.Dispose();
        _socket?.Dispose();
    }

    private void _hubService_RemoteLogEvent(object? sender, Admin.NET.Core.Hub.RemoteLog e)
    {
        if (_socket == null) return;
        Task.Run(async() =>
        {
            
            var buffer = new WebSocketData { Type = 0, Log = e.Adapt<RemoteLog>() }.ToJson().GetBytes();
            await _socket?.SendAsync(
                new ArraySegment<byte>(buffer),
                System.Net.WebSockets.WebSocketMessageType.Binary, true,

                _source.Token);
        },_source.Token);
     
    }

    private void _hubService_MessageEvent(object? sender, Admin.NET.Core.Hub.InformModel e)
    {
        if (_socket == null) return;
        Task.Run(async () =>
        {
            var buffer = new WebSocketData { Type=1,Inform=e.Adapt<InformModel>()}.ToJson().GetBytes();
            await _socket?.SendAsync(
                new ArraySegment<byte>(buffer),
                System.Net.WebSockets.WebSocketMessageType.Binary, true,

                _source.Token);
        }, _source.Token);
    }

    private CancellationTokenSource _source;
    [AllowAnonymous]
    [Route("/ws")]
    public async Task Get()
    {
        if (App.HttpContext.WebSockets.IsWebSocketRequest)
        {
            _source = new CancellationTokenSource();
             _socket = await App.HttpContext.WebSockets.AcceptWebSocketAsync();
            await Echo(_socket);
            
        }
        else
        {
            App.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }
    private  async Task Echo(System.Net.WebSockets.WebSocket webSocket)
    {
       

       

        while (true)
        {
            if (_source.IsCancellationRequested) return;
          

            await Task.Delay(1000);

           
        }

      
    }

    /// <summary>
    /// 分页查询程序管理
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "Page")]
    public async Task<SqlSugarPagedList<ProgramInfoOutput>> Page([FromQuery] ProgramInfoInput input)
    {
        var query = _rep.AsQueryable()

                    .InnerJoin<ProgramStatus>((x, y) => x.Id == y.ProgramId).WhereIF(!string.IsNullOrWhiteSpace(input.name), (x, y) => x.Name.Contains(input.name.Trim())).OrderBy((x, y) => x.Id)
                    .Select((x, y) => new ProgramInfoOutput
                    {
                        id = x.Id,
                        name = x.Name,
                        runpath = x.RunPath,
                        ipaddress = x.IPAddress,
                        programtype = x.ProgramType,
                        runtime = x.Runtime,
                        cpu = y.Cpu,
                        ram = y.Ram,
                        status = y.Status,
                        statusdes = y.StatusDes,
                        statustime = y.UpdateTime,
                        remark = x.Remark,
                        Message=y.Remark
                    })
;

        var datas = await query.ToPagedListAsync(input.Page, input.PageSize);

       var equipCounts=await _rep.Context.Queryable<EquipInfo>().Where(x=>x.IsDelete==false).GroupBy(x => x.ProgramId).Select(group=>new {group.ProgramId,Count=SqlSugar.SqlFunc.AggregateCount(group.ProgramId)}).ToListAsync();

        datas.Items.ForEach(x =>
        {
           
            // 时间没有刷新，离线
            if ((x.statustime != null && DateTime.Now.Subtract(x.statustime.Value).TotalSeconds > 120) || x.statustime==null)
            {
                x.status = 0;
            }
            var count=equipCounts.FirstOrDefault(y=>y.ProgramId == x.id);
            if (count == null)
            {
                x.equiptotal = 0;
            }
            else
            x.equiptotal = count.Count;

        });
        return datas;
    }

    /// <summary>
    /// 增加程序管理
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Add")]
    public async Task Add(AddProgramAllInput input)
    {
        var entity = input.Adapt<ProgramInfo>();
        await _rep.InsertAsync(entity);
    }

    /// <summary>
    /// 删除程序管理
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Delete")]
    [UnitOfWork]
    public async Task Delete(DeleteProgramAllInput input)
    {
        var entity = await _rep.GetFirstAsync(u => u.Id == input.id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        // 删除程序
        await _rep.DeleteAsync(entity);
        // 删除状态
        await _rep.Context.Deleteable<ProgramStatus>().Where(x => x.ProgramId == entity.Id).ExecuteCommandAsync();
    }
    /// <summary>
    /// 执行程序命令
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "ExecuteControl")]
    [AllowAnonymous]
    public async Task ExecuteControl(WebControlCommand input)
    {
       
        if (input.ControlType == IotContract.Enums.ProgramControlType.Command)
        {
           var write= await _grpcService.WriteEquips(new List<IotContract.Models.Clients.OperationWriteCommand>
            {
                new IotContract.Models.Clients.OperationWriteCommand
                {
                    ProtobufType=input.ProtobufType,
                    EquipId=input.EquipId,
                    Data="100",
                    Id=Guid.NewGuid().ToString()
                }
            });
            if (write == false)
            {
                throw Oops.Oh("执行失败");
            }
        }
        else
        {
            long equipInfo = input.ProgramId;
            if (equipInfo == 0 && !string.IsNullOrEmpty(input.EquipNum))
            {
                equipInfo = await _rep.Context.Queryable<EquipInfo>().Where(z=>z.Num== input.EquipNum).Select(z=>z.ProgramId).FirstAsync();
            }
      
           
           var result = await _grpcService.ControlCommand(new List<IotContract.Models.Clients.ClientControlCommand>{ new IotContract.Models.Clients.ClientControlCommand
            {

                ControlType = input.ControlType,
                ProgramId =  equipInfo,
                EquipId = input.EquipId,
                ProtobufType = input.ProtobufType
            }
            }) ;
            if (!string.IsNullOrEmpty(result))
            {
                throw Oops.Oh(result);
            }
        }
      

      
    }
  


    /// <summary>
    /// 更新程序管理
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Update")]
    public async Task Update(UpdateProgramAllInput input)
    {
        var entity = input.Adapt<ProgramInfo>();
        await _rep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
    }

    /// <summary>
    /// 获取程序管理
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "Detail")]
    public async Task<ProgramInfo> Get([FromQuery] QueryByIdProgramAllInput input)
    {
        return await _rep.GetFirstAsync(u => u.Id == input.id);
    }

    /// <summary>
    /// 获取程序管理列表
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "List")]
    public async Task<List<ProgramInfoOutput>> List([FromQuery] ProgramInfoInput input)
    {
        return await _rep.AsQueryable().Select<ProgramInfoOutput>().ToListAsync();
    }

   
}

